package com.atguigu.gulimall.product.advice;

import com.atguigu.common.utils.CommonResponse;
import com.atguigu.gulimall.product.exception.GuliProductRuntimeException;
import com.atguigu.gulimall.product.exception.enums.ExceptionErrorCodeEnum;
import com.atguigu.gulimall.product.utils.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolationException;
import javax.validation.UnexpectedTypeException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Objects;

/**
 * Global exception handler.
 */
@Slf4j
@ControllerAdvice
public final class GlobalExceptionHandler {

    /**
     * Handle exception.
     *
     * @param ex exception
     * @return response result
     */
    @SuppressWarnings("rawtypes")
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public CommonResponse handleException(final Exception ex) {
        log.error("handler error", ex);
        if (ex instanceof GuliProductRuntimeException) {
            return ResponseUtil.fail((GuliProductRuntimeException) ex);
        } else if (ex instanceof MethodArgumentNotValidException) {
            return ResponseUtil.fail(ExceptionErrorCodeEnum.PARAMETER_ERROR.getErrorCode(),
                    Objects.requireNonNull(((MethodArgumentNotValidException) ex).getBindingResult().getFieldError()).getDefaultMessage());
        } else if (ex instanceof BindException) {
            return ResponseUtil.fail(ExceptionErrorCodeEnum.PARAMETER_ERROR.getErrorCode(),
                    Objects.requireNonNull(((BindException) ex).getBindingResult().getFieldError()).getDefaultMessage());
        } else if (ex instanceof ConstraintViolationException) {
            String errorMsg = ex.getMessage();
            if (StringUtils.isNotEmpty(errorMsg) && errorMsg.contains(":")) {
                errorMsg = errorMsg.substring(errorMsg.indexOf(":") + 1).trim();
            }
            return ResponseUtil.fail(ExceptionErrorCodeEnum.PARAMETER_ERROR.getErrorCode(), errorMsg);
        } else if (ex instanceof UnexpectedTypeException) {
            return ResponseUtil.fail(ExceptionErrorCodeEnum.PARAMETER_TYPE_ERROR);
        } else if (ex instanceof BindException) {
            return ResponseUtil.fail(ExceptionErrorCodeEnum.PARAMETER_ERROR.getErrorCode(),
                    Objects.requireNonNull(((BindException) ex).getBindingResult().getAllErrors().get(0)).getDefaultMessage());
        } else if (ex instanceof UndeclaredThrowableException) {
            return ResponseUtil.fail(ExceptionErrorCodeEnum.PARAMETER_ERROR.getErrorCode(),
                    Objects.requireNonNull((UndeclaredThrowableException) ex).getUndeclaredThrowable().getMessage());
        }
        return ResponseUtil.fail(ExceptionErrorCodeEnum.INTERNAL_ERROR);
    }
}
